﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Configuration;
using System.IO;
using System.Text.RegularExpressions;
using OperationPlugins.Configurations;

namespace OperationPlugins.Compositions
{
    internal sealed class CompositionContainerFactory
    {
        /// <summary>
        /// Creates the composition container.
        /// </summary>
        /// <returns>The composition container.</returns>
        internal static CompositionContainer CreateCompositionContainer()
        {
            AggregateCatalog assemblies = new AggregateCatalog();

            foreach (ComposablePartCatalog assembly in GetAssemblyCatalogs())
            {
                assemblies.Catalogs.Add(assembly);
            }
                    
            CompositionContainer cc = new CompositionContainer(assemblies, true);
            return cc;
        }

        private static IEnumerable<ComposablePartCatalog> GetAssemblyCatalogs()
        {
            foreach (string directory in GetDirectories())
            {
                foreach (string file in GetFiles(directory))
                {
                    yield return new AssemblyCatalog(file);
                }
            }
        }

        private static IEnumerable<string> GetDirectories()
        {
            CompositionSection configurations = CompositionSection.Instance;
            if (configurations == null)
            {
                throw new ConfigurationErrorsException("Could not find the operationPluginsCompositions configuration section. Please check your App.config or Web.config!");
            }

            string root = AppDomain.CurrentDomain.BaseDirectory;
            yield return root;

            foreach (DirectoryElement element in configurations.Directories)
            {
                string path = Path.Combine(root, element.Directory);
                if (Directory.Exists(path) == false)
                {
                    throw new ConfigurationErrorsException(string.Format("Could not find the configured composition assembly directory {0}. Please check your App.config or Web.config!", path));
                }
                yield return path;
            }
        }

        private static IEnumerable<string> GetFiles(string directory)
        {
            CompositionSection configurations = CompositionSection.Instance;
            if (configurations == null)
            {
                throw new ConfigurationErrorsException("Could not find the operationPluginsCompositions configuration section. Please check your App.config or Web.config!");
            }


            foreach (string fileName in Directory.GetFiles(directory, "*.dll"))
            {                
                FileInfo file = new FileInfo(fileName);

                bool ignoreFile = false;
              
                foreach (RegexPatternElement ignore in configurations.IgnoreAssemblies)
                {
                    if (Regex.IsMatch(file.Name, ignore.Pattern))
                    {
                        ignoreFile = true;
                        break;
                    }
                }

                if (ignoreFile == false)
                {
                    yield return fileName;
                }
            }
        }

    }
}
